package org.epanetgrid.otimizacao.tui;

import static org.epanetgrid.otimizacao.tui.ArgOptions.BOMBAS_MUTADAS;
import static org.epanetgrid.otimizacao.tui.ArgOptions.CONTROLE_INICIAL;
import static org.epanetgrid.otimizacao.tui.ArgOptions.ELITISMO;
import static org.epanetgrid.otimizacao.tui.ArgOptions.FO;
import static org.epanetgrid.otimizacao.tui.ArgOptions.FO_CHAVEAMENTOS;
import static org.epanetgrid.otimizacao.tui.ArgOptions.FO_CUSTO_TOTAL;
import static org.epanetgrid.otimizacao.tui.ArgOptions.FO_NIVEIS;
import static org.epanetgrid.otimizacao.tui.ArgOptions.GRID;
import static org.epanetgrid.otimizacao.tui.ArgOptions.LOG;
import static org.epanetgrid.otimizacao.tui.ArgOptions.MAX_GERACOES;
import static org.epanetgrid.otimizacao.tui.ArgOptions.MIN_VIAVEIS;
import static org.epanetgrid.otimizacao.tui.ArgOptions.MUTACAO;
import static org.epanetgrid.otimizacao.tui.ArgOptions.MUTACAO_BITABIT;
import static org.epanetgrid.otimizacao.tui.ArgOptions.MUTACAO_INTERVALO;
import static org.epanetgrid.otimizacao.tui.ArgOptions.POP_EXT;
import static org.epanetgrid.otimizacao.tui.ArgOptions.PORC_XO_NORMAL;
import static org.epanetgrid.otimizacao.tui.ArgOptions.PROB_MUT_DIRECIONADA;
import static org.epanetgrid.otimizacao.tui.ArgOptions.PROB_MUT_NORMAL_BIT;
import static org.epanetgrid.otimizacao.tui.ArgOptions.PROB_MUT_NORMAL_INTERVALO;
import static org.epanetgrid.otimizacao.tui.ArgOptions.PROB_XO_DIRECIONADO;
import static org.epanetgrid.otimizacao.tui.ArgOptions.PROB_XO_NORMAL;
import static org.epanetgrid.otimizacao.tui.ArgOptions.REPRESENTATIVAS;
import static org.epanetgrid.otimizacao.tui.ArgOptions.SELECAO;
import static org.epanetgrid.otimizacao.tui.ArgOptions.SELECAO_SUS;
import static org.epanetgrid.otimizacao.tui.ArgOptions.SELECAO_TORNEIO;
import static org.epanetgrid.otimizacao.tui.ArgOptions.TAM_POP_INICIAL;
import static org.epanetgrid.otimizacao.tui.ArgOptions.TEMPO_MAX;

import java.io.IOException;
import java.util.Arrays;

import org.apache.log4j.PatternLayout;
import org.apache.log4j.RollingFileAppender;
import org.epanetgrid.data.DataFacade;
import org.epanetgrid.model.epanetNetWork.DefaultNetWork;
import org.epanetgrid.model.epanetNetWork.NetWork;
import org.epanetgrid.otimizacao.OtimizadorBuilder;
import org.epanetgrid.otimizacao.log.AGLogger;

public class BuilderConfigurator {

	private static NetWork getNetwork(String inpFile, String operacaoFile) throws IOException {
		return new DataFacade().createNetWorkFromFile(inpFile, operacaoFile);
	}
	
	public static void configureBuilder(OtimizadorBuilder builder, ArgOptions line) {

		try {
			NetWork network = getNetwork(line.getNetworkFile(), line.getOperacaFile());

			builder.setNetwork((DefaultNetWork) network);

			if( line.hasOption( LOG ) ) {
				initLogger(line.getOptionValue( LOG ));
			}
			
			if( line.hasOption( TAM_POP_INICIAL ) ) {
				int tamanhoPopulacaoInicial = new Integer(line.getOptionValue( TAM_POP_INICIAL ));
				builder.setTamanhoPopulacaoInicial(tamanhoPopulacaoInicial);
			}

			if( line.hasOption( POP_EXT ) ) {
				double populacaoExterna = new Double(line.getOptionValue( POP_EXT ));
				builder.setPorcPopulacaoExterna(populacaoExterna);
			}

			if( line.hasOption( ELITISMO ) ) {
				double porcElitismo = new Double(line.getOptionValue( ELITISMO ));
				builder.setPorcElitismo(porcElitismo);
			}

			if( line.hasOption( PORC_XO_NORMAL ) ) {
				double porcXOnormal = new Double(line.getOptionValue( PORC_XO_NORMAL ));
				builder.setPorcCrossoverNormal(porcXOnormal);
			}

			if( line.hasOption( PROB_XO_NORMAL ) ) {
				double probXOnormal = new Double(line.getOptionValue( PROB_XO_NORMAL ));
				builder.setProbXOnormal(probXOnormal);
			}

			if( line.hasOption( PROB_XO_DIRECIONADO ) ) {
				double probXOdirecionado = new Double(line.getOptionValue( PROB_XO_DIRECIONADO ));
				builder.setProbXOdirecionado(probXOdirecionado);
			}

			if( line.hasOption( PROB_MUT_NORMAL_INTERVALO ) ) {
				double probMutNormalIntervalo = new Double(line.getOptionValue( PROB_MUT_NORMAL_INTERVALO ));
				builder.setProbMutNormalIntervalo(probMutNormalIntervalo);
			}

			if( line.hasOption( PROB_MUT_NORMAL_BIT ) ) {
				double probMutNormalBit = new Double(line.getOptionValue( PROB_MUT_NORMAL_BIT ));
				builder.setProbMutNormalBitAbit(probMutNormalBit);
			}

			if( line.hasOption( PROB_MUT_DIRECIONADA ) ) {
				double probMutDirecionada = new Double(line.getOptionValue( PROB_MUT_DIRECIONADA ));
				builder.setProbMutDirecionada(probMutDirecionada);
			}

			if( line.hasOption( BOMBAS_MUTADAS ) ) {
				double porcBombasMutadas = new Double(line.getOptionValue( BOMBAS_MUTADAS ));
				builder.setPorcaoDeBombasMutadas(porcBombasMutadas);
			}

			if( line.hasOption( GRID ) ) {
				builder.setUsarGrid(true);
				int individuosPorTask = new Integer(line.getOptionValue( GRID ));
				builder.setIndPorTask(individuosPorTask);
			}

			if( line.hasOption( CONTROLE_INICIAL ) ) {
				String filePath = line.getOptionValue( CONTROLE_INICIAL );
				builder.setUsarControle(true);
				DefaultNetWork networkControl = (DefaultNetWork) new DataFacade().createNetWorkFromFile(filePath);
				builder.setControleInicial(networkControl.getFullControls());
			}

			if( line.hasOption( MUTACAO ) ) {
				String tipoDeMutacao = line.getOptionValue( MUTACAO );
				if (tipoDeMutacao.equals(MUTACAO_INTERVALO)) {
					builder.setUsarMutacaoEsther(true);
				} else if (tipoDeMutacao.equals(MUTACAO_BITABIT)) {
					builder.setUsarMutacaoEsther(false);
				} else {
					throw new IllegalArgumentException(tipoDeMutacao + ": O tipo de mutação deve ser: " +
							MUTACAO_INTERVALO + " ou " + MUTACAO_BITABIT);
				}
			}

			if( line.hasOption( SELECAO ) ) {
				String tipoDeSelecao = line.getOptionValue( SELECAO );
				if (tipoDeSelecao.equals(SELECAO_TORNEIO)) {
					builder.setUsarSUS(false);
				} else if (tipoDeSelecao.equals(SELECAO_SUS)) {
					builder.setUsarSUS(true);
				} else {
					throw new IllegalArgumentException(tipoDeSelecao + ": O tipo de seleção deve ser: " +
							SELECAO_TORNEIO + " ou " + SELECAO_SUS);
				}
			}

			if( line.hasOption( REPRESENTATIVAS ) ) {
				int numRepresentativas = new Integer(line.getOptionValue( REPRESENTATIVAS ));
				builder.setQuantRepresentativas(numRepresentativas);
			}
			
			if( line.hasOption( FO ) ) {
				String[] fos = line.getOptionValues( FO );

				for (String fo : fos) {
					if (fo.equals(FO_CUSTO_TOTAL)) {
						builder.setUsarCustoTotal(true);
					} else if (fo.equals(FO_CHAVEAMENTOS)) {
						builder.setUsarNumeroChaveamentos(true);
					} else if (fo.equals(FO_NIVEIS)) {
						builder.setUsarNiveisDeTanques(true);
					} else {
						throw new IllegalArgumentException("Opção(ões) de função objetivo inválida(s): " + fo);
					}
				}
				
				System.out.println("FOs: " + Arrays.toString(fos));

			}

			if( line.hasOption( MAX_GERACOES ) ) {
				builder.setUsarNumMaxGeracoes(true);
				int numMaxGeracoes = new Integer(line.getOptionValue( MAX_GERACOES ));
				builder.setGeracaoMaxima(numMaxGeracoes);
			}

			if( line.hasOption( MIN_VIAVEIS ) ) {
				builder.setUsarNumeroIndViaveis(true);
				int minViaveis = new Integer(line.getOptionValue( MIN_VIAVEIS ));
				builder.setQuantMinViaveis(minViaveis);
			}

			if( line.hasOption( TEMPO_MAX ) ) {
				builder.setUsarTempoMax(true);
				long tempoMax = new Long(line.getOptionValue( TEMPO_MAX ));
				builder.setTempoMaximo(tempoMax);
			}

		}
		catch (IOException e) {
			System.err.println("Erro na leitura de arquivos.\nDetalhes:");
			e.printStackTrace();
		}

	}

	private static void initLogger(String logFile) {
		try {
			PatternLayout layout = new PatternLayout("%-5p: %d %2x - %m%n");
			RollingFileAppender appender = new RollingFileAppender(layout, logFile);
			appender.setMaxFileSize ("30MB");
	        appender.setMaxBackupIndex(5);
	        AGLogger.getInstance().addAppender(appender);
	        AGLogger.getInstance().addOption(AGLogger.DEBUG);
	        AGLogger.getInstance().addOption(AGLogger.INFO);
	        AGLogger.getInstance().addOption(AGLogger.WARN);
		} catch (IOException e) {
			e.printStackTrace();
		}
        
	}
	
}
